package org.ciallo.simplemusicplayer.util;

import android.content.ContentUris;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import org.ciallo.simplemusicplayer.data.model.Song;
import timber.log.Timber;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author Jukomu
 * @Description: 从歌曲文件路径提取元数据并构建Song对象的工具类
 * @Package: org.ciallo.simplemusicplayer.util
 * @Project: SimpleMusicPlayer
 * @name: SongMetadataUtil
 * @Date: 2025/5/27-03:37
 * @Filename: SongMetadataUtil
 */
public class SongMetadataUtil {

    private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart");


    /**
     * 从给定的歌曲文件路径提取元数据，并尝试构建一个Song对象。
     * 注意：此方法无法获取如 MediaStore ID、artistId、albumId、外部专辑封面URI、
     * 添加日期、拼音、收藏状态等需要外部数据源或应用状态的属性。
     *
     * @param songPath 歌曲文件的绝对路径。
     * @return 一个填充了部分元数据的 Song 对象；如果路径无效或无法读取元数据，则返回null。
     */
    public static Song loadSongFromPath(String songPath) {
        if (songPath == null || songPath.isEmpty()) {
            Timber.w("Song path is null or empty.");
            return null;
        }

        File songFile = new File(songPath);
        if (!songFile.exists() || !songFile.isFile()) {
            Timber.w("Song file does not exist or is not a file: %s", songPath);
            return null;
        }

        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(songPath);

            // 提取核心元数据
            String title = extractTitle(retriever);
            String artist = extractArtist(retriever);
            String album = extractAlbum(retriever);
            long duration = extractDuration(retriever); // 单位已经是毫秒
            String yearStr = extractYear(retriever);
            String trackNumStr = extractTrackNumber(retriever);
            String genre = extractGenre(retriever);
            String composer = extractComposer(retriever);
            String discNumStr = extractDiscNumber(retriever);
            String mimeType = extractMimeType(retriever);
            String albumArtist = extractAlbumArtist(retriever);
            // 内嵌封面不是直接的Song属性，而是用于生成Bitmap，但这里不处理，因为Song模型存储的是URI

            // 解析和转换数据
            int year = 0;
            if (yearStr != null && !yearStr.isEmpty()) {
                try {
                    year = Integer.parseInt(yearStr.substring(0, Math.min(4, yearStr.length()))); // 有些年份可能带月份
                } catch (NumberFormatException e) {
                    Timber.w("Could not parse year: %s", yearStr);
                }
            }

            int trackNumber = 0;
            if (trackNumStr != null && !trackNumStr.isEmpty()) {
                try {
                    // 音轨号可能是 "5/12" 这种格式，我们只取前面的数字
                    String[] trackParts = trackNumStr.split("/");
                    trackNumber = Integer.parseInt(trackParts[0].trim());
                } catch (NumberFormatException e) {
                    Timber.w("Could not parse track number: %s", trackNumStr);
                }
            }
            int discNumber = 0;
            if (discNumStr != null && !discNumStr.isEmpty()) {
                try {
                    String[] discParts = discNumStr.split("/");
                    discNumber = Integer.parseInt(discParts[0].trim());
                } catch (NumberFormatException e) {
                    Timber.w("Could not parse disc number: %s", discNumStr);
                }
            }


            // 文件系统相关属性
            long size = songFile.length();
            String folderPath = songFile.getParent();
            if (folderPath == null) folderPath = "";

            // 创建Song对象，使用System.currentTimeMillis()作为临时的ID，或者0/-1
            // artistId, albumId, albumArtUri, dateAdded, pinyins, favorite 等字段设为默认值
            Song song = new Song(
                    System.currentTimeMillis(), // 临时ID，实际应用中会由MediaStore或数据库生成
                    TextUtils.isEmpty(title) ? songFile.getName() : title, // 如果标题为空，用文件名
                    TextUtils.isEmpty(artist) ? "未知歌手" : artist,
                    -1L, // artistId 未知
                    TextUtils.isEmpty(album) ? "未知专辑" : album,
                    -1L, // albumId 未知
                    songPath,
                    duration,
                    null, // albumArtUri - 内嵌封面需要单独处理，或者这个字段用于外部URI
                    folderPath,
                    songFile.lastModified(), // 使用文件最后修改时间作为近似的添加时间
                    trackNumber,
                    year,
                    size,
                    mimeType,
                    null, // titlePinyin - 需要PinyinUtil
                    albumArtist,
                    null, // artistPinyin
                    null, // albumPinyin
                    genre,
                    composer,
                    discNumber,
                    1.0f, // default playbackSpeed
                    0L,   // default lastPlayedPosition
                    false,// default isFavorite
                    null, // lyricsPath
                    null  // onlineLyricsUrl
            );
            return song;

        } catch (Exception e) {
            Timber.e(e, "Failed to retrieve metadata for song: %s", songPath);
            return null;
        } finally {
            try {
                retriever.release(); // 必须释放 MediaMetadataRetriever
            } catch (IOException ex) {
                Timber.e(ex, "Failed to release MediaMetadataRetriever.");
            }
        }
    }

    // --- 单独提取各个属性的方法 ---

    /**
     * 从 MediaMetadataRetriever 中提取歌曲标题。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 歌曲标题，如果未找到则返回 null。
     */
    public static String extractTitle(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
    }

    /**
     * 从 MediaMetadataRetriever 中提取艺术家名称。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 艺术家名称，如果未找到则返回 null。
     */
    public static String extractArtist(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
    }

    /**
     * 从 MediaMetadataRetriever 中提取专辑名称。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 专辑名称，如果未找到则返回 null。
     */
    public static String extractAlbum(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
    }

    /**
     * 从 MediaMetadataRetriever 中提取专辑艺术家名称。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 专辑艺术家名称，如果未找到则返回 null。
     */
    public static String extractAlbumArtist(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
    }


    /**
     * 从 MediaMetadataRetriever 中提取歌曲时长。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 歌曲时长（毫秒），如果未找到或解析失败则返回 0。
     */
    public static long extractDuration(MediaMetadataRetriever retriever) {
        String durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        if (durationStr != null) {
            try {
                return Long.parseLong(durationStr);
            } catch (NumberFormatException e) {
                Timber.w("Could not parse duration: %s", durationStr);
            }
        }
        return 0;
    }

    /**
     * 从 MediaMetadataRetriever 中提取发行年份。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 发行年份字符串，如果未找到则返回 null。
     */
    public static String extractYear(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
    }

    /**
     * 从 MediaMetadataRetriever 中提取音轨号。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 音轨号字符串 (可能包含 "X/Y" 格式)，如果未找到则返回 null。
     */
    public static String extractTrackNumber(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);
    }

    /**
     * 从 MediaMetadataRetriever 中提取CD碟号。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return CD碟号字符串 (可能包含 "X/Y" 格式)，如果未找到则返回 null。
     */
    public static String extractDiscNumber(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER);
    }

    /**
     * 从 MediaMetadataRetriever 中提取流派。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 流派字符串，如果未找到则返回 null。
     */
    public static String extractGenre(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
    }

    /**
     * 从 MediaMetadataRetriever 中提取作曲家。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return 作曲家字符串，如果未找到则返回 null。
     */
    public static String extractComposer(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
    }

    /**
     * 从 MediaMetadataRetriever 中提取MIME类型。
     *
     * @param retriever 已设置数据源的 MediaMetadataRetriever 实例。
     * @return MIME类型字符串，如果未找到则返回 null。
     */
    public static String extractMimeType(MediaMetadataRetriever retriever) {
        return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE);
    }


    /**
     * 从歌曲文件路径中提取内嵌封面 (复用CoverUtil的功能，但放在这里便于独立使用)。
     *
     * @param songPath 歌曲文件路径。
     * @return Bitmap 对象，如果不存在或提取失败则返回 null。
     */
    public static Bitmap extractEmbeddedArtwork(String songPath) {
        if (songPath == null || songPath.isEmpty()) {
            return null;
        }
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(songPath);
            byte[] art = retriever.getEmbeddedPicture();
            if (art != null) {
                return BitmapFactory.decodeByteArray(art, 0, art.length);
            }
        } catch (Exception e) {
            Timber.e(e, "Error retrieving embedded picture from (SongMetadataUtil): %s", songPath);
        } finally {
            try {
                retriever.release();
            } catch (IOException e) {
                Timber.e(e, "Error releasing MediaMetadataRetriever in extractEmbeddedArtwork.");
            }
        }
        return null;
    }

    /**
     * 获取专辑封面的 URI (通过专辑ID)
     *
     * @param albumId 专辑ID (来自 MediaStore.Audio.Albums._ID)
     * @return 专辑封面的 Uri，如果不存在则返回 null
     */
    public static Uri getAlbumArtUri(long albumId) {
        if (albumId < 0) return null;
        try {
            return ContentUris.withAppendedId(ALBUM_ART_URI, albumId);
        } catch (Exception e) {
            Timber.e(e, "Error getting album art URI for albumId: %d", albumId);
            return null;
        }
    }

    /**
     * 从给定的 Uri 加载 Bitmap
     *
     * @param context Context
     * @param artUri  封面的 Uri
     * @return Bitmap 对象，如果加载失败则返回 null
     */
    public static Bitmap loadBitmapFromUri(Context context, Uri artUri) {
        if (context == null || artUri == null) {
            return null;
        }
        Bitmap bitmap = null;
        ParcelFileDescriptor pfd = null;
        try {
            pfd = context.getContentResolver().openFileDescriptor(artUri, "r");
            if (pfd != null) {
                FileDescriptor fd = pfd.getFileDescriptor();
                // 配置 BitmapFactory.Options 以避免OOM，例如进行采样
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 1; // 调整采样率以适应显示大小
                // options.inJustDecodeBounds = true; // 如果需要先获取尺寸
                // BitmapFactory.decodeFileDescriptor(fd, null, options);
                // options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
                // options.inJustDecodeBounds = false;
                bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
            }
        } catch (FileNotFoundException e) {
            Timber.w(e, "Art URI not found: %s", artUri.toString());
        } catch (OutOfMemoryError e) {
            Timber.e(e, "OutOfMemoryError loading art URI: %s", artUri.toString());
            // 可以尝试更小的采样率或释放一些内存
        } catch (Exception e) {
            Timber.e(e, "Error loading art URI: %s", artUri.toString());
        } finally {
            if (pfd != null) {
                try {
                    pfd.close();
                } catch (IOException e) {
                    Timber.e(e, "Error closing ParcelFileDescriptor");
                }
            }
        }
        return bitmap;
    }

    /**
     * 从歌曲文件路径中提取内嵌封面
     *
     * @param songPath 歌曲文件路径
     * @return Bitmap 对象，如果不存在或提取失败则返回 null
     */
    public static Bitmap getEmbeddedPicture(String songPath) {
        if (songPath == null || songPath.isEmpty()) {
            return null;
        }
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(songPath);
            byte[] art = retriever.getEmbeddedPicture();
            if (art != null) {
                return BitmapFactory.decodeByteArray(art, 0, art.length);
            }
        } catch (Exception e) {
            Timber.e(e, "Error retrieving embedded picture from: %s", songPath);
        } finally {
            try {
                retriever.release();
            } catch (IOException e) {
                Timber.e(e, "Error releasing MediaMetadataRetriever");
            }
        }
        return null;
    }


    /**
     * 计算 BitmapFactory.Options.inSampleSize 的值
     *
     * @param options   BitmapFactory.Options
     * @param reqWidth  期望宽度
     * @param reqHeight 期望高度
     * @return 合适的 inSampleSize 值
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
}
